﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "ObjectBrowser.h"
#include "IDock.h"
#include "IUiManager.h"
#include "IUiViewEvent.h"
#include "IDockManager.h"
#include "IUiViewEventArgs.h"
#include "IUiDocumentEvent.h"
#include "IUserTransaction.h"
#include "IUiViewEventHandler.h"
#include "IUiDocumentEventArgs.h"
#include "IUiDocumentViewManager.h"
#include "IUiDocumentEventHandler.h"

#include "IFieldProxy.h"
#include "GNodeWrapper.h"
#include "PropertyInstanceWidget.h"
#include "PropertyInstanceSetting.h"
#include "Journal/ObjectBrowserRecorderAndReplayerCreator.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

/// 本文件是界面实现的辅助类，不包含GDMP API的演示内容

using namespace gcmp;
using namespace Sample;

ObjectBrowser::ObjectBrowser()
    : Sample::CObjectBrowserWidget(nullptr)
    , m_isTopVisible(false)
    , m_isNeedUpdate(false)
    , m_opUserTransaction(nullptr)
    , m_curUiDocId(-1)
    , m_bTransactionIsCommitting(false)
    , m_canPropertyTableBeUpdated(true)
    , m_pObjectWrapper(nullptr)
    , m_isEnabled(false)
{
    setObjectName(QStringLiteral("ObjectBrowser"));

    setApplyButtonText(QString::fromStdWString(GBMP_TR(L"应用")));

    connect(this, SIGNAL(sigPropertyEditButtonClicked(int)), this, SLOT(onPropertyEditButtonClicked(int)), Qt::UniqueConnection);
    connect(this, SIGNAL(DropDownListIndexChange(int, int)), this, SLOT(OnDropDownListIndexChange(int, int)), Qt::UniqueConnection);
    
    std::wstring className = StringUtil::ToWString(this->metaObject()->className());
    ObjectBrowserRecorderAndReplayerCreator::RegisterToJournal(className);

    setMinimumWidth(230);
}

ObjectBrowser::~ObjectBrowser()
{
    std::wstring className = StringUtil::ToWString(this->metaObject()->className());
    ObjectBrowserRecorderAndReplayerCreator::UnregisterToJournal(className);
}

void ObjectBrowser::SetEnabled(bool bEnable)
{
    m_isEnabled = bEnable;
}

void ObjectBrowser::UpdateStatus()
{
    UpdatePropertyTable();
}

void Sample::ObjectBrowser::SetDataAndUpdate(IGraphicsNode_Wrapper* pObjectWrapper)
{
    m_pObjectWrapper = pObjectWrapper;
    UpdatePropertyTable(true);
}

QSize ObjectBrowser::sizeHint() const
{
    return QSize(230, 900);
}

void ObjectBrowser::showEvent(QShowEvent *event)
{
    UpdatePropertyTable();
}

bool ObjectBrowser::IsDockTopWidget()
{
    QWidget *parent = dynamic_cast<QWidget*>(this->parent());
    return isVisible() && parent != nullptr && parent->isVisible();
}

ObjectBrowser* ObjectBrowser::Get()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空",L"GDMP",L"2024-03-30");
    IDockManager* pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDockManager, L"pDockManager为空",L"GDMP",L"2024-03-30");
    IDock* pDock = pDockManager->GetDock(ObjectBrowser::GetTypeName());
    if (!pDock)
        return nullptr;
    ObjectBrowser* pPropPalette = dynamic_cast<ObjectBrowser*>(pDock->GetWidget());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPropPalette, L"pPropPalette为空",L"GDMP",L"2024-03-30");
    return pPropPalette;
}

ObjectBrowser* ObjectBrowser::GetOrCreate()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空", L"GDMP", L"2024-03-30");
    IDockManager* pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDockManager, L"pDockManager为空", L"GDMP", L"2024-03-30");

    IDock* pDock = pDockManager->GetDock(ObjectBrowser::GetTypeName());
    bool isNotCreate = false;
    if (!pDock)
    {
        OwnerPtr<IDock> opDock = pDockManager->CreateDock(ObjectBrowser::GetTypeName(), L"GRep浏览器");
        OwnerPtr<ObjectBrowser> opPropertyWidget = NEW_AS_OWNER_PTR(ObjectBrowser);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPropertyWidget, L"opPropertyWidget为空", L"GDMP", L"2024-03-30");
        opDock->SetWidget(TransferOwnership(opPropertyWidget));
        pDockManager->AddDock(TransferOwnership(opDock), DockArea::Right, DockOrientation::Vertical);
        pDock = pDockManager->GetDock(ObjectBrowser::GetTypeName());
        isNotCreate = true;
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDock, L"pDock为空", L"GDMP", L"2024-03-30");
    if (!isNotCreate)
    {
        pDock->Show();
        pDock->Raise();
    }

    ObjectBrowser* pPropPalette = dynamic_cast<ObjectBrowser*>(pDock->GetWidget());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPropPalette, L"pPropPalette为空", L"GDMP", L"2024-03-30");
    return pPropPalette;
}

void ObjectBrowser::DisplayPanel()
{
    ObjectBrowser* pPropPalette = GetOrCreate();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPropPalette, L"pPropPalette为空",L"GDMP",L"2024-03-30");
    pPropPalette->UpdatePropertyTable();
}

void ObjectBrowser::OnPropertyValueChanged(int groupIndex, int propertyIndex)
{
    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIPW != nullptr, L"pIPW为空",L"GDMP",L"2024-03-30");
    CPropertyItem* pItem = pIPW->GetPropertyByIndex(groupIndex, propertyIndex);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem != nullptr, L"pItem不能为空",L"GDMP",L"2024-03-30");

    int fieldId = pItem->UniqueID();
    ParametersArrayDict& parameterArrayDict = m_pObjectWrapper->GetParameters();

    for (auto& pair : parameterArrayDict)
    {
        ParametersArray& parameterArray = pair.second;
        // 添加分组下的所有参数
        for (int loop = 0; loop < (int)parameterArray.size(); ++loop)
        {
            IFieldProxy* pFieldProxy = parameterArray[loop].get();
            if (pFieldProxy->GetUniqueId() != fieldId)
            {
                continue;
            }

            QVariant strParamValue = pItem->GetValue();
            FieldType fType = pFieldProxy->GetFieldType();

            if (fType == FieldType::Bool)
            {
                bool newValue = strParamValue.toBool();
                pFieldProxy->UpdateValue(newValue);
            }
            else if (fType == FieldType::Enum || fType == FieldType::String)
            {
                std::wstring newValue = strParamValue.toString().toStdWString();
                pFieldProxy->UpdateValue(newValue);
            }
            else if (fType == FieldType::Int)
            {
                bool ok = false;
                int intValue = strParamValue.toInt(&ok);
                if (ok)
                {
                    pFieldProxy->UpdateValue(intValue);
                }
            }
            else if (fType == FieldType::Double)
            {
                bool ok = false;
                double doubleValue = strParamValue.toDouble(&ok);
                if (ok)
                {
                    pFieldProxy->UpdateValue(doubleValue);
                }
            }
        }
    }

    // 基类修改属性项事件处理
    CObjectBrowserWidget::OnPropertyValueChanged(groupIndex, propertyIndex);
}

void ObjectBrowser::OnApply()
{
    if (IsPropertyValueChanged() == false)
    {
        if (!m_bTransactionIsCommitting && m_opUserTransaction != nullptr && m_opUserTransaction->IsStarted())
        {
            m_opUserTransaction->Rollback();
        }
        return;
    }

    // 基类"应用"事件处理
    CObjectBrowserWidget::OnApply();
    if (m_onApplyCallBack)
    {
        m_onApplyCallBack(m_pObjectWrapper);
    }
    UpdatePropertyTable();
}

void ObjectBrowser::OnDropDownListIndexChange(int groupIndex, int propertyIndex)
{
    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIPW != nullptr, L"pIPW为空",L"GDMP",L"2024-03-30");
    CPropertyItem* pItem = pIPW->GetPropertyByIndex(groupIndex, propertyIndex);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pItem != nullptr, L"pItem不能为空",L"GDMP",L"2024-03-30");
}

void ObjectBrowser::onPropertyEditButtonClicked(int uniquiID)
{
}

void ObjectBrowser::UpdatePropertyTable(bool bRebuild /*= false*/)
{
    if (!m_canPropertyTableBeUpdated)
        return;

    CInstancePropertyWidget* pIPW = GetComponentInstancePropertyWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pIPW != nullptr, L"pIPW为空",L"GDMP",L"2024-03-30");
    pIPW->RemoveAllPropertyGroup();

    if (!m_pObjectWrapper)
    {
        return;
    }

    ParametersArrayDict& parameterArrayDict = m_pObjectWrapper->GetParameters();

    int index = 0;
    for (auto& pair : parameterArrayDict)
    {
        ParametersArray& parameterArray = pair.second;
        std::wstring groupName = pair.first;
        pIPW->AddPropertyGroup(index, QString::fromStdWString(groupName), QString::fromStdWString(groupName));

        // 添加分组下的所有参数
        for (int loop = 0; loop < (int)parameterArray.size(); ++loop)
        {
            IFieldProxy* pFieldProxy = parameterArray[loop].get();

            std::wstring paramName = pFieldProxy->GetFieldName();
            std::wstring paramDescription = pFieldProxy->GetDescription();
            std::wstring paramValue = pFieldProxy->GetFieldValue();
            int uniqueId = pFieldProxy->GetUniqueId();

            CPropertyItem* pItem = pIPW->AddProperty(index, uniqueId, QString::fromStdWString(paramName),
                QString::fromStdWString(paramDescription), QString::fromStdWString(paramValue), false, esLineEdit);

            pItem->SetOriginParamName(QString::fromStdWString(paramName));

            SetPropertyItemValue(pItem, pFieldProxy);
        }
        index++;
    }

    pIPW->RefreshView(bRebuild);
}

QStringList GetQStringList(std::vector<std::wstring> stringList)
{
    QStringList qStrList;
    for (auto it : stringList)
    {
        qStrList.append(QString::fromStdWString(it));
    }
    return qStrList;
}

void ObjectBrowser::SetPropertyItemValue(CPropertyItem* pItem, IFieldProxy* pFieldProxy)
{
    pItem->SetEnable(false);
    std::wstring paramDisplayStr = pFieldProxy->GetFieldValue();
    FieldType fieldType = pFieldProxy->GetFieldType();

    if (fieldType == FieldType::Enum)
    {
        pItem->SetEditStyle(esDropDown);
        pItem->SetComboboxItems(GetQStringList(pFieldProxy->GetEnumList()));

        pItem->SetValue(QString::fromStdWString(paramDisplayStr));
    }
    else if (fieldType == FieldType::String)
    {
        pItem->SetEditStyle(esLineEdit);
        pItem->SetValue(QString::fromStdWString(pFieldProxy->GetFieldValue()));
    }
    else if (fieldType == FieldType::Bool)
    {
        pItem->SetEditStyle(esBool);
        pItem->SetValue(pFieldProxy->GetValueAsBool() ? Qt::Checked : Qt::Unchecked);
    }
    else if (fieldType == FieldType::Int)
    {
        pItem->SetEditStyle(esLineEdit);
        pItem->SetValue(QString::fromStdWString(pFieldProxy->GetFieldValue()));
    }
    else if (fieldType == FieldType::Double)
    {
        pItem->SetEditStyle(esLineEdit);
        pItem->SetValue(QString::fromStdWString(pFieldProxy->GetFieldValue()));
    }
    else
    {
        pItem->SetEditStyle(esColorList);

        int colorVal = pFieldProxy->GetValueAsInt();
        unsigned char* colorData = (unsigned char*)(&colorVal);
        int red = colorData[0];
        int green = colorData[1];
        int blue = colorData[2];
        int alpha = colorData[3];
        QVariant color(QColor(red, green, blue, alpha));
        pItem->SetValue(color);
    }
    pItem->SetEnable(!pFieldProxy->IsReadOnly() && m_isEnabled);
}

